#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "mycharts.h"
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
#include <QMutexLocker>
#include "general.h"
#include "excelreader.h"
#include <QMessageBox>
#include <QDirIterator>
#include <QThread>
#include <QProgressDialog>
#include <QPointer>
#include <QProgressBar>
#include <QFile>
#include <QTimer>
#include <QCoreApplication>



/**
 * @brief : 构造函数
 * @author : PindleSkin
 * @date : 2025-10-17
 * @details : 1. 初始化ui
 * @param : parent 父窗口指针
 * @return : None
 */
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->label_app_title->setText(QApplication::applicationName());
    setWindowTitle(QApplication::applicationName());

    // 设置WA_StyledBackground属性以确保样式表能够正确应用
    this->setAttribute(Qt::WA_StyledBackground, true);
    ui->centralwidget->setAttribute(Qt::WA_StyledBackground, true);

    // 应用扁平化样式表（已在main.cpp中设置，此处不再重复设置）

    m_lastOpenDir = QApplication::applicationDirPath();

    ui->toolButton_dataSheet->setDisabled(true);
    ui->toolButton_guidewaySheet->setDisabled(true);
    ui->toolButton_log->setDisabled(true);

    // 连接信号槽
    connect(ui->toolButton_config, SIGNAL(clicked()), this, SLOT(slotConfigFileSet()));
    connect(ui->toolButton_log, SIGNAL(clicked()), this, SLOT(slotLogFileSet()));
    connect(ui->toolButton_guidewaySheet, SIGNAL(clicked()), this, SLOT(slotGuidewaySheetFileSet()));
    connect(ui->toolButton_dataSheet, SIGNAL(clicked()), this, SLOT(slotDataSheetFileSet()));
    connect(ui->pushButton_read_log, SIGNAL(clicked()), this, SLOT(slotReadLog()));
    connect(ui->pushButton_generate, SIGNAL(clicked()), this, SLOT(slotRun()));
}

MainWindow::~MainWindow()
{
    delete ui;
}


/**
 * @brief : ui->toolButton_config按钮的槽函数，用于设置ui->lineEdit_config的显示路径
 * @author : PindleSkin
 * @date : 2025-10-17
 * @details : 1. 打开文件对话框，选择config文件所在目录
 * @param : None
 * @return : None
 */
void MainWindow::slotConfigFileSet()
{
    ui->lineEdit_config->setText(getFilePathFromFileDialog(CONFIG_DIALOG_TITLE, m_lastOpenDir, CONFIG_DIALOG_FILTER));
    if(!ui->lineEdit_config->text().isEmpty()) {
        bool configReadRet = m_scriptReader.openFile(ui->lineEdit_config->text());
        if(configReadRet){
            ui->toolButton_guidewaySheet->setEnabled(true);
            ui->toolButton_dataSheet->setEnabled(true);
            ui->toolButton_log->setEnabled(true);
        }
    }
}

/**
 * @brief : ui->toolButton_log按钮的槽函数，用于设置ui->lineEdit_log的显示路径
 * @author : PindleSkin
 * @date : 2025-10-17
 * @details : 1. 打开文件对话框，选择log文件所在目录
 * @param : None
 * @return : None
 */
void MainWindow::slotLogFileSet()
{
    // QString filePath = getFilePathFromFileDialog(LOG_DIALOG_TITLE, m_lastOpenDir, LOG_DIALOG_FILTER);

    // QString fileDir = getDirFromFilePath(filePath);
    QString fileDir = QFileDialog::getExistingDirectory(this, LOG_DIALOG_TITLE, m_lastOpenDir);
    m_lastOpenDir = fileDir;
    ui->lineEdit_log->setText(fileDir);
}


/**
 * @brief : ui->toolButton_guidewaySheet按钮的槽函数，用于设置ui->lineEdit_guidewaySheet的显示路径，
 *          并读取文教中的所有表格，用于更新ui->comboBox_guidewaySheet的下拉选项
 * @author : PindleSkin
 * @date : 2025-10-17
 * @details : 1. 读取guideway sheet中的所有表格，将表格名称添加到ui->comboBox_guidewaySheet的下拉选项中
 *            2. 读取guideway sheet中的所有track_id，将track_id添加到ui->comboBox_trackId的下拉选项中
 * @param : None
 * @return : None
 */
void MainWindow::slotGuidewaySheetFileSet()
{
    QString path = getFilePathFromFileDialog(EXCEL_DIALOG_TITLE, m_lastOpenDir, EXCEL_DIALOG_FILTER);
    if (path.isEmpty()) return;
    ui->lineEdit_guidewaySheet->setText(path);
    ui->comboBox_trackId->clear();
    ExcelReader er;
    // if(er.openFile(u8R"(D:\Code\curve-drawer\SHJCJY_P4_Guideway_DATA(正线+车辆段+试车线，转OBCU数据用)_20250214.xlsx)"))
    if(er.openFile(ui->lineEdit_guidewaySheet->text())) {
        ui->comboBox_guidewaySheet->clear();
        ui->comboBox_guidewaySheet->addItems(er.getSheetsName());
        connect(ui->comboBox_guidewaySheet, SIGNAL(currentTextChanged(QString)), this, SLOT(slotSelectGuidewaySheet()));
    }

}


/**
 * @brief : ui->comboBox_guidewaySheet按钮的槽函数，用于设置ui->lineEdit_guidewaySheet的显示路径，
 *          并读取文教中的所有表格，用于更新ui->comboBox_guidewaySheet的下拉选项
 * @author : PindleSkin
 * @date : 2025-10-17
 * @details : 1. 读取guideway sheet中的所有表格，将表格名称添加到ui->comboBox_guidewaySheet的下拉选项中
 *            2. 读取guideway sheet中的所有track_id，将track_id添加到ui->comboBox_trackId的下拉选项中
 * @param : None
 * @return : None
 */
void MainWindow::slotSelectGuidewaySheet()
{
    // m_guidewaySheetData.clear();
    // 读取guideway sheet
    ExcelReader t_guideway_sheet_reader;
    t_guideway_sheet_reader.openFile(ui->lineEdit_guidewaySheet->text());

    // guideway工作表选择成功
    if(t_guideway_sheet_reader.selectSheet(ui->comboBox_guidewaySheet->currentText())){
        // 根据配置表读取所需内容
        QXlsx::Worksheet* guideway_sheet = t_guideway_sheet_reader.getWorkSheet();
        int rowCount = guideway_sheet->dimension().rowCount();
        QStringList combobox_id_list;

        // 根据guideway sheet的配置读取guideway sheet
        QHash<QString, int> guide_way_config = m_scriptReader.getGuideWaySheetConfig();

        int track_id_row = guide_way_config[CONFIG_GUIDEWAY_SHEET_TRACK_ID_KEY];
        int edge_id_row = guide_way_config[CONFIG_GUIDEWAY_SHEET_EDGE_ID_KEY];
        int edge_strt_offset_row = guide_way_config[CONFIG_GUIDEWAY_SHEET_EDGE_START_OFFSET_KEY];

        int last_track_id = 0;
        for (auto row = 1; row <= rowCount ; ++row) {
            // 读取track_id
            auto track_id = guideway_sheet->read(row, track_id_row).toInt();
            
            // 读取edge_id
            auto edge_id = guideway_sheet->read(row, edge_id_row).toInt();

            if (track_id == 0 && edge_id == 0) continue;

            // 读取edge_start_offset
            auto edge_start_offset = guideway_sheet->read(row, edge_strt_offset_row).toDouble();

            if (track_id != 0 && track_id != last_track_id) {
                last_track_id = track_id;
                m_track_edges_data[QString::number(track_id)] = QVector<std::shared_ptr<int>>();
                combobox_id_list.append(QString::number(track_id));
            }

            m_track_edges_data[QString::number(last_track_id)].append(std::make_shared<int>(edge_id));

            // 记录edge的起始里程
            m_edge_start_offset_data[edge_id] = std::make_shared<double>(edge_start_offset);

        }
        ui->comboBox_trackId->clear();
        ui->comboBox_trackId->addItems(combobox_id_list);

    }
}


/**
 * @brief : ui->toolButton_dataSheet按钮的槽函数，用于设置ui->lineEdit_dataSheet的显示路径，
 *          并读取文教中的所有表格，用于更新ui->comboBox_dataSheet的下拉选项
 * @author : PindleSkin
 * @date : 2025-10-17
 * @details : 1. 读取data sheet中的所有表格，将表格名称添加到ui->comboBox_dataSheet的下拉选项中
 * @param : None
 * @return : None
 */
void MainWindow::slotDataSheetFileSet()
{
    m_dataSheetData.clear();
    QString path = getFilePathFromFileDialog(EXCEL_DIALOG_TITLE, m_lastOpenDir, EXCEL_DIALOG_FILTER);
    if (path.isEmpty()) {
        return;
    }
    ui->lineEdit_dataSheet->setText(path);
    ScriptReader::DataSheetInfo dataSheetInfo = m_scriptReader.getDataSheetConfig();
    ExcelReader er;
    if(!er.openFile(ui->lineEdit_dataSheet->text())) return;

    if(er.openFile(ui->lineEdit_dataSheet->text())) {
        if(er.selectSheet(dataSheetInfo.sheet_name)) {
            QXlsx::Worksheet* data_sheet = er.getWorkSheet();
            m_dataSheetData = readProfiles(data_sheet, dataSheetInfo);
        }
    }

}



/**
 * @brief : ui->pushButton_read_log按钮的槽函数，用于读取日志文件
 * @author : PindleSkin
 * @date : 2025-10-17
 * @details : 1. 读取日志文件中的所有变量，将变量添加到ui->comboBox_log的下拉选项中
 * @param : None
 * @return : None
 */
void MainWindow::slotReadLog()
{
    if(!ui->toolButton_guidewaySheet->isEnabled() || !ui->toolButton_log->isEnabled() || ui->lineEdit_log->text().isEmpty()) {
        QMessageBox::warning(this ,u8"警告", u8"请检查输入文件是否已设置完成");
    } else {
        m_logData.clear();
        QProgressDialog * progressDialog = new QProgressDialog;
        progressDialog->setWindowTitle(u8"日志文件载入进度");
        progressDialog->setWindowModality(Qt::WindowModal);
        progressDialog->setFixedWidth(400);
        
        // 应用扁平化样式表（与主窗口保持一致）
        QFile file(":/qss/flat_style.qss");
        if (file.open(QFile::ReadOnly)) {
            QString styleSheet = QLatin1String(file.readAll());
            progressDialog->setStyleSheet(styleSheet);
        }

        // 获取进度条控件（QProgressBar）
        QProgressBar *progressBar = progressDialog->findChild<QProgressBar*>();
        if (progressBar) {
            // 设置进度条的水平对齐方式为居中
            progressBar->setAlignment(Qt::AlignCenter); // 进度文本居中（可选）

            // 获取进度条的父布局（通常是 QVBoxLayout）
            QLayout *layout = progressBar->parentWidget()->layout();
            if (layout) {
                // 设置进度条在布局中的水平对齐方式为居中
                layout->setAlignment(progressBar, Qt::AlignHCenter);
            }
        }


        progressDialog->show();
        progressDialog->setLabelText(u8"正在读取变量,请耐心等待......");
        QApplication::processEvents();

        QDirIterator it(ui->lineEdit_log->text(),
                        QStringList("*.log"),  // 筛选 .log 文件
                        QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks,
                        QDirIterator::Subdirectories); // 递归子目录
        m_logData.clear();
        QVector<QFileInfo> logFiles;

        while (it.hasNext()) {
            it.next();
            logFiles.append(it.fileInfo());
        }
        // 按修改时间排序（旧到新）
        std::sort(logFiles.begin(), logFiles.end(),
                  [](const QFileInfo& a, const QFileInfo& b) {
                      return a.lastModified() < b.lastModified();
                  });

        progressDialog->setRange(0, logFiles.length());


        // // 读取guideway sheet
        LogReader *log = new LogReader;
        QThread *thread = new QThread;
        log->moveToThread(thread);

        connect(log, &LogReader::readFinished, this, &MainWindow::slotLogReadFinished);
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
        connect(this, &MainWindow::finished, thread, &QThread::quit);
        connect(this, &MainWindow::finished, log, &LogReader::deleteLater);
        // 进度条删除由延迟关闭逻辑处理，不在此处连接deleteLater
        connect(this, &MainWindow::startReadLog, log, &LogReader::getValueFromLog);
        connect(this, &MainWindow::sendFile, log, &LogReader::addFile);
        connect(log, &LogReader::sendTotalVarCount, this, [=](int number){
            progressDialog->setRange(0, number);
        });


        connect(log, &LogReader::sendReadVar, this, [=](int index){
            progressDialog->setValue(index);
            // qDebug()<< "index" << index;
            QApplication::processEvents();
        });

        connect(thread, &QThread::started, this, [=](){
            QMutexLocker locker(&mutex); // 加锁保护共享数据
            QPointer<MainWindow> guard(this);   // 检查this指针

            if(guard) { // 检查this指针
                // 输出结果
                int maxCount = 0;
                for (auto const &fileInfo : std::as_const(logFiles)) {
                    emit sendFile(fileInfo.absoluteFilePath());
                    maxCount++;
                }
                // 只设置一次进度条范围
                // progressDialog->setRange(0, maxCount);
                progressDialog->setAutoClose(true); // 不自动关闭，由readFinished信号处理
                progressDialog->show();

                QString cycleFeatures = m_scriptReader.getCycleFeatures();
                std::shared_ptr<QJsonArray> valueArray = std::make_shared<QJsonArray>(m_scriptReader.getCycleValues());

                // 读取日志
                emit startReadLog(cycleFeatures, valueArray);
                ui->pushButton_read_log->setDisabled(true);
            }

        });

        thread->start();

    }
}

/**
 * @brief : ui->pushButton_run按钮的槽函数，开始执行
 * @param : None
 * @return : None
 */
void MainWindow::slotRun()
{
    readRangeAndPointList();

    // 从配置文件中读取纵坐标范围
    auto axis_y_range = m_scriptReader.getAxisRange(CONFIG_AXIS_Y_KEY);
    auto axis_x_tick_count = m_scriptReader.getAxisRange(CONFIG_AXIS_X_KEY);

    auto curve_list = m_scriptReader.getCurveInfo();

    if (axis_y_range.isEmpty() || axis_x_tick_count.isEmpty() || curve_list.isEmpty()) {
        QMessageBox::warning(this ,u8"警告", u8"请检查输入文件是否齐全");
        return;
    }

    MyCharts chart;
    chart.resize(1200, 800);
    QPen pen;
    pen.setStyle(Qt::SolidLine);


    // 计算Y轴的范围
    int y_range = (axis_y_range[2] - axis_y_range[1]) / axis_y_range[0] + 1;

    // 计算X轴的范围(使用标准库分别向上和向下按100取整)
    m_axisXRange.first = std::floor(m_axisXRange.first / 100.0) * 100.0;
    m_axisXRange.second = std::ceil(m_axisXRange.second / 100.0) * 100.0;
    int x_range = (m_axisXRange.second - m_axisXRange.first) / axis_x_tick_count[0] + 1;



    chart.setAxisRange(axis_y_range[1], axis_y_range[2], "%.0f", y_range, MyCharts::ENUM_ORIENTATION::Vertical);
    // chart.setAxisRange(22700,24000, "%.0f", axis_x_tick_count[0], MyCharts::Horizontal);
    chart.setAxisRange(m_axisXRange.first, m_axisXRange.second, "%.0f", x_range, MyCharts::ENUM_ORIENTATION::Horizontal);
    chart.setAxisLabel(QColor(0, 0, 0), QFont("Arial", 10), MyCharts::ENUM_ORIENTATION::Vertical);
    chart.setAxisLabel(QColor(0, 0, 0), QFont("Arial", 10), MyCharts::ENUM_ORIENTATION::Horizontal);
    chart.setAxisGridLine(QPen(QColor(50, 50, 50, 20)), MyCharts::ENUM_ORIENTATION::Vertical);
    chart.setAxisGridLine(QPen(QColor(50, 50, 50, 20)), MyCharts::ENUM_ORIENTATION::Horizontal);
    chart.setAxisTitleName(m_scriptReader.getAxisTitle(CONFIG_AXIS_Y_KEY), QFont("Arial", 12), QColor(0, 0, 0), MyCharts::ENUM_ORIENTATION::Vertical);
    chart.setAxisTitleName(m_scriptReader.getAxisTitle(CONFIG_AXIS_X_KEY), QFont("Arial", 12), QColor(0, 0, 0), MyCharts::ENUM_ORIENTATION::Horizontal);

    int n = 0;
    for(auto const &[name, list] : m_curveData.asKeyValueRange()) {
        if(name.contains(":")) {
            QString t_name = name.split(":")[0];
            QPen pen(QColor(curve_list[n++].color));
            pen.setStyle(Qt::DashLine);
            chart.drawCurve(t_name.replace(" ", ""), list, pen);
        }
        else {
            chart.drawCurve(name, list, QPen(QColor(curve_list[n++].color)));
        }
    }
    QString title = u8"Track" + QString::number(ui->comboBox_trackId->currentText().toInt()) + "-GD" + QString::number(ui->comboBox_orientation->currentText().toInt());

    chart.setChartTitle(title, QFont("Arial", 12), QColor(0, 0, 0));

    chart.saveToPicture(QString("./SpeedPrifile_%1.png").arg(title));

}

void MainWindow::slotLogReadFinished(QHash< QString, QVector< std::shared_ptr<int> > > ret)
{
    m_logData = ret;

    QStringList keys = m_logData.keys();
    QStringList orientation_list;
    for(auto const& key : std::as_const(keys)) {
        if(key == m_scriptReader.getComboboxVarNameFromLog()) {
            for(auto const &orientation : std::as_const(m_logData[key])) {
                if(orientation)
                    if(!orientation_list.contains(QString::number(*orientation - 1)))orientation_list.append(QString::number(*orientation - 1));
            }
        }
    }
    ui->comboBox_orientation->clear();
    ui->comboBox_orientation->addItems(orientation_list);
    emit finished();
    ui->pushButton_read_log->setEnabled(true);
}


/**
 * @brief : 弹出文件选择对话框，将选中的文件路径作为返回值返回
 * @param title : 弹出对话框的显示标题
 * @param defaultDir : 对话框默认打开的文件路径
 * @param filter : 用于过滤文件类型的格式字符串
 * @return : QString类型，返回选中文件的文件路径，如果未选中或取消，则返回空
 */
QString MainWindow::getFilePathFromFileDialog(const QString& title, const QString& defaultDir, const QString& filter)
{
    QString filePath = QFileDialog::getOpenFileName(Q_NULLPTR, title, defaultDir, filter);
    m_lastOpenDir = getDirFromFilePath(filePath);
    return filePath;
}

/**
 * @brief : 从传入的文件路径中获取文件所在目录
 * @param filePath : 文件路径
 * @return : QString类型，返回文件路径中的文件所在目录，如果不存在或路径无效，则返回空
 */
QString MainWindow::getDirFromFilePath(const QString& filePath)
{
    QFileInfo fi(filePath);
    QString fileDir;
    if(fi.exists()){
        fileDir = fi.path();
    }
    return fileDir;
}

void MainWindow::readRangeAndPointList()
{
    QStringList vars = m_logData.keys();
    if (vars.isEmpty()) return;
    int cycleNumber = m_logData[vars[0]].length();

    m_axisXRange.first = 0;
    m_axisXRange.second = 0;

    // 获取要绘图的track所有的edge list
    QVector<int> edge_list;
    for (auto const [key, vector] : m_track_edges_data.asKeyValueRange()) {
        if(key.toInt() == ui->comboBox_trackId->currentText().toInt()) {
            for(auto const& edge_id_ptr : std::as_const(vector)) {
                edge_list.append(*edge_id_ptr);
            }
        }
    }

    // // 获取hex轴范围
    // for (auto const& edge_id : std::as_const(edge_list)) {
    //     double edge_start_offset = *m_edge_start_offset_data[edge_id];
    //     if (m_axisXRange.first == 0 || edge_start_offset < m_axisXRange.first) {
    //         m_axisXRange.first = static_cast<int>(edge_start_offset);
    //     }
    //     if (edge_start_offset > m_axisXRange.second) {
    //         m_axisXRange.second = static_cast<int>(edge_start_offset);
    //     }
    // }



    // 获取绘制曲线
    auto curve_list = m_scriptReader.getCurveInfo();

    int flag = false;
    m_curveData.clear();
    for(auto n = 0; n < curve_list.length(); n++) {
        // 获取曲线X轴计算公式中需要替换的变量列表
        QStringList x_var_list = getValueFromStrByRegex(curve_list[n].x_formula, u8R"(\{([^\}]+)\})");
        QStringList y_var_list = getValueFromStrByRegex(curve_list[n].y_formula, u8R"(\{([^\}]+)\})");

        // 遍历所有周期，获取log中曲线的数据
        if(curve_list[n].source == CONFIG_FROM_LOG_KEY) {
            QVector<std::shared_ptr<QPointF>> point_list;

            // 遍历所有周期
            for(auto cycle = 0; cycle < cycleNumber; cycle++) {
                // 读取X轴公式
                QString x_cacl_str = curve_list[n].x_formula;
                // 读取Y轴公式
                QString y_cacl_str = curve_list[n].y_formula;

                // 遍历日志中的所有变量,替换x轴计算公式中的变量名
                for(auto const& varName : std::as_const(vars)) {
                    // 如果公式中包含该变量，则进行每周期替换
                    if(x_var_list.contains(varName)) {
                        // 判断该变量的当前周期是否为空
                        if(m_logData[varName][cycle]) {
                            // 将公式中的变量名替换为当前周期值
                            // qDebug()<< *m_logData[varName][cycle];
                            x_cacl_str = x_cacl_str.replace(u8R"({)" + varName + u8R"(})", QString::number(*m_logData[varName][cycle]));
                            flag = true;
                        } else {
                            flag = false;
                        }
                    }
                }
                // qDebug()<< "cycle" << cycle << x_cacl_str;
                // 遍历所有需要替换的变量，如果有“：”的则需要使用查表后的数据替换
                if(flag) {
                    for(auto const& var : std::as_const(x_var_list)){
                        if(var.contains(":")) {
                            QString subKey = var.split(":")[1].replace(" ", "");
                            if(m_logData[subKey][cycle]) {
                                int edge = *m_logData[subKey][cycle];
                                // x_cacl_str = x_cacl_str.replace(u8R"({)" + var + u8R"(})", QString::number(edgeInfo[edge]));
                                x_cacl_str = x_cacl_str.replace(u8R"({)" + var + u8R"(})", QString::number(*m_edge_start_offset_data[edge]));
                            } else {
                                flag = false;
                            }
                        }
                    }
                }
                // qDebug()<<x_cacl_str;


                // 遍历日志中的所有变量,替换y轴计算公式中的变量名
                if(flag) {
                    for(auto const& varName : std::as_const(vars)) {
                        // 如果公式中包含该变量，则进行每周期替换
                        if(y_var_list.contains(varName)) {
                            // 遍历该变量的所有周期值
                            if(m_logData[varName][cycle]) {
                                y_cacl_str = y_cacl_str.replace(u8R"({)" + varName + u8R"(})", QString::number(*m_logData[varName][cycle]));
                                for(auto const& var : std::as_const(y_var_list)){
                                    if(var.contains(":")) {
                                        QString subKey = var.split(":")[1].replace(" ", "");
                                        if(m_logData[subKey][cycle]) {
                                            int edge = *m_logData[subKey][cycle];
                                            // y_cacl_str = y_cacl_str.replace(u8R"({)" + var + u8R"(})", QString::number(edgeInfo[edge]));
                                            y_cacl_str = y_cacl_str.replace(u8R"({)" + var + u8R"(})", QString::number(*m_edge_start_offset_data[edge]));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // 遍历所有需要替换的变量，如果有“：”的则需要使用查表后的数据替换
                if(flag) {
                    for(auto const& var : std::as_const(y_var_list)){
                        if(var.contains(":")) {
                            QString subKey = var.split(":")[1].replace(" ", "");
                            if(m_logData[subKey][cycle]) {
                                int edge = *m_logData[subKey][cycle];
                                // y_cacl_str = y_cacl_str.replace(u8R"({)" + var + u8R"(})", QString::number(edgeInfo[edge]));
                                y_cacl_str = y_cacl_str.replace(u8R"({)" + var + u8R"(})", QString::number(*m_edge_start_offset_data[edge]));
                            } else {
                                flag = false;
                            }
                        }
                    }
                }

                if(flag && m_logData["Log_EdgeId"][cycle]) {

                    if(edge_list.contains(*m_logData["Log_EdgeId"][cycle]));
                }

                if(flag && m_logData["Log_Orientation"][cycle] && m_logData["Log_EdgeId"][cycle]) {
                    if((*m_logData["Log_Orientation"][cycle] == ui->comboBox_orientation->currentText().toInt() + 1) && edge_list.contains(*m_logData["Log_EdgeId"][cycle])) {
                        int x = caculation<float>(x_cacl_str);
                        float y = caculation<float>(y_cacl_str);
                        // qDebug()<< x << x_cacl_str;
                        if(m_axisXRange.first == 0) {
                            m_axisXRange.first = x;
                        }

                        if(m_axisXRange.second < x) m_axisXRange.second = x;
                        std::shared_ptr<QPointF> sptr_point = std::make_shared<QPointF>(x, y);
                        point_list.append(sptr_point);

                    }
                }
            }
            m_curveData[curve_list[n].name] = point_list;


        }

        QVector<SpeedProfile> profile_list = getSortedProfile(ui->comboBox_trackId->currentText().toInt(), ui->comboBox_orientation->currentText().toInt());
        if(curve_list[n].source == CONFIG_FROM_DATA_SHEET_KEY) {
            // for(auto const [name, list] : track_hash.asKeyValueRange()) {
            QVector<std::shared_ptr<QPointF>> point_list;
            for(auto const & value : std::as_const(profile_list)) {
                std::shared_ptr<QPointF> point_start= std::make_shared<QPointF>(*value.track_offset_pair.first, *value.speed);
                std::shared_ptr<QPointF> point_end= std::make_shared<QPointF>(*value.track_offset_pair.second, *value.speed);
                point_list.append(point_start);
                point_list.append(point_end);
            }
            m_curveData[curve_list[n].name] = point_list;
            // }
        }
    }

}

// QHash< int, QVector<int> > MainWindow::getEdgeInfo()
// {
//     QStringList keys = m_track_edges_data.keys();

//     QHash< int, QVector<int> > ret_hash;

//     for(auto n = 0; n < m_guidewaySheetData[keys[0]].length(); n++) {
//         for(auto const &key : std::as_const(keys)) {
//             if( *m_guidewaySheetData[key][n] == ui->comboBox_trackId->currentText().toInt()) {
//                 ret_hash[*m_guidewaySheetData[CONFIG_GUIDEWAY_SHEET_EDGE_ID_KEY][n]] = *m_guidewaySheetData[CONFIG_GUIDEWAY_SHEET_EDGE_OFFSET_KEY][n];
//             }
//         }
//     }

//     return ret_hash;
// }

// 排序函数
void MainWindow::sortSpeedProfileList(QVector<MainWindow::SpeedProfile>& list) {
    std::sort(list.begin(), list.end(), [](const SpeedProfile& a, const SpeedProfile& b) {
            // 防御性检查：确保 track_offset_pair.first 有效
            if (!a.track_offset_pair.first || !b.track_offset_pair.first) {
            // 可根据需求定义空指针的排序规则（例如将空值视为最小值）
            // 这里简单返回 false，但实际应根据业务逻辑调整
            return false;
        }
        return *(a.track_offset_pair.first) < *(b.track_offset_pair.first);
    });
}


QVector<MainWindow::SpeedProfile> MainWindow::getSortedProfile(const int& track_id, const int& orientation)
{
    QVector<MainWindow::SpeedProfile> ret;

    auto const list = m_dataSheetData;
    for(auto const& profile : std::as_const(list)) {
        if(*profile.direction == orientation && *profile.track_id == track_id) {
            ret.append(profile);
        }
    }
    sortSpeedProfileList(ret);

    return ret;
}



MainWindow::SpeedProfile MainWindow::readOneProfile(
    const QXlsx::Worksheet* const data_sheet,
    int* const row,
    const ScriptReader::DataSheetInfo& dataInfo,
    bool* const ret)
{
    MainWindow::SpeedProfile profile;
    *ret = true;
    for(auto const col : std::as_const(dataInfo.data_dict)) {
        if(data_sheet->read(*row, col).isNull()) {
            (*ret) = false;
        }
    }
    if(*ret) {
        do {
            // 读取direction
            auto t_direction = data_sheet->read(*row, dataInfo.data_dict[CONFIG_DATA_SHEET_DIRECTION_KEY]).toInt(ret);
            if(!(*ret)) {
                break;
            }
            profile.direction = std::make_shared<int>(t_direction);

            // 读取track id
            auto t_track_id = data_sheet->read(*row, dataInfo.data_dict[CONFIG_DATA_SHEET_TRACK_ID_KEY]).toInt(ret);
            if(!(*ret)) {
                break;
            }
            profile.track_id = std::make_shared<int>(t_track_id);

            // 读取track offset_1
            auto t_track_offset_1 = static_cast<double>(data_sheet->read(*row, dataInfo.data_dict[CONFIG_DATA_SHEET_TRACK_OFFSET_KEY]).toDouble(ret));
            if(!(*ret)) {
                break;
            }

            // 读取speed
            auto t_speed = data_sheet->read(*row, dataInfo.data_dict[CONFIG_DATA_SHEET_SPEED_KEY]).toInt(ret);
            if(!(*ret)) {
                break;
            }
            profile.speed = std::make_shared<int>(t_speed);

            // 读取track offset_2
            auto t_track_offset_2 = static_cast<double>(data_sheet->read(++(*row), dataInfo.data_dict[CONFIG_DATA_SHEET_TRACK_OFFSET_KEY]).toDouble(ret));
            if(!(*ret)) {
                break;
            }

            t_track_offset_1 > t_track_offset_2 ? profile.track_offset_pair = QPair<std::shared_ptr<double>, std::shared_ptr<double>>(std::make_shared<double>(t_track_offset_2), std::make_shared<double>(t_track_offset_1)) :
                profile.track_offset_pair = QPair<std::shared_ptr<double>, std::shared_ptr<double>>(std::make_shared<double>(t_track_offset_1), std::make_shared<double>(t_track_offset_2));
            *ret = true;
        } while(0);
    }
    return profile;
}

QVector<MainWindow::SpeedProfile> MainWindow::readProfiles(
    const QXlsx::Worksheet* const data_sheet,
    const ScriptReader::DataSheetInfo& dataInfo
    )
{
    QVector<MainWindow::SpeedProfile> ret_list;
    if(data_sheet) {
        int rowCount = data_sheet->dimension().rowCount();
        // std::shared_ptr<int> s_p_direction, s_p_track_id, s_p_speed;
        // QPair<std::shared_ptr<double>, std::shared_ptr<double>> offset_pair(Q_NULLPTR, Q_NULLPTR);

        for(auto row = 1; row <= rowCount; row++) {
            bool ret = true;
            MainWindow::SpeedProfile profile = readOneProfile(data_sheet, &row, dataInfo, &ret);
            if(ret) {
                ret_list.append(profile);
            }
        }
    }
    return ret_list;
}

